<!--
 * @Description: 右键菜单
 * @Version: 2.0
 * @Autor: wiz
 * @Date: 2023-05-15 14:09:35
 * @LastEditors: swc
 * @LastEditTime: 2024-08-24 11:47:27
-->
<!--
******功能应用组件模板******
功能应用组件:是最终应用程序的根组件,它注册在系统功能里。例如：权限设置，开发模块，逻辑引擎等
引用注册在全局Tsrv.compBox里, 参数需要compID+name+funName写全。
参考开发模块devModal写法
-->
<template>
  <div class="contextmenu" v-show="value">
    <Menu
      :width="menuWidth"
      :visible.sync="visible"
      :style="menuStyle"
      @on-select="onSelect"
    >
      <template v-for="(item, idx) of list">
        <div :key="idx">
          <MenuItem
            v-if="$srv.noValue(item.children)"
            :name="item.name"
            v-show="$srv.getx(item, 'isShow', true)"
            :class="{
              disabledMenuItem: item.disabled,
              menuItemHover: !item.disabled
            }"
            @click.native="disabledClick(item)"
          >
            <div class="item-content">
              <Icon :custom="item.icon" />
              <span>{{ $srv.getI18nByPath(item.title) }}</span>
            </div>
          </MenuItem>
          <Submenu
            v-else
            :name="item.name"
            v-show="$srv.getx(item, 'isShow', true)"
          >
            <template #title>
              <div class="item-content">
                <Icon :custom="item.icon" />
                <span>{{ $srv.getI18nByPath(item.title) }}</span>
              </div>
            </template>
            <template v-for="(child, i) of item.children">
              <div :key="i">
                <MenuItem
                  :name="child.name"
                  v-show="$srv.getx(child, 'isShow', true)"
                  :class="{
                    disabledMenuItem: item.disabled,
                    menuItemHover: !item.disabled
                  }"
                  @click.native="disabledClick(child)"
                >
                  <div class="item-content">
                    <Icon :custom="child.icon" />
                    <span> {{ $srv.getI18nByPath(child.title) }}</span>
                  </div>
                </MenuItem>
              </div>
            </template>
          </Submenu>
        </div>
      </template>
    </Menu>
  </div>
</template>

<script lang="ts">
import { T_srv, Tsrv, ifs, vue } from '@/services';
import { N_oContextMenu } from '@/types';

@T_srv.comp
export default class oContextMenu extends vue {
  @T_srv.prop({
    required: true,
    type: Array
  })
  list: Array<N_oContextMenu.I_menuItem>; // [{name:xxx,title:xxx}]

  @T_srv.prop({
    required: false,
    type: Function
  })
  callback: Function; // [{name:xxx,title:xxx}]

  @T_srv.prop({
    required: false,
    type: Object
  })
  displayPosition: N_oContextMenu.I_showPosition; // {clientX:xxx,clientY:xxx}

  @T_srv.prop({
    required: false,
    default: 'auto',
    validator: val => {
      return /^(auto|\d+px|\d+)$/.test(val) || !Tsrv.utils.isNumber(val);
    }
  })
  width: string | number; // 菜单宽度

  @T_srv.prop({
    required: false,
    type: Boolean,
    default: false
  })
  value: boolean;

  /* 父组件compBoxInfo */
  @T_srv.prop({
    required: false,
    type: Object,
    default: null
  })
  compBoxInfo: ifs.I_compBoxInfo;

  @T_srv.watch('value')
  onValueChange(newVal) {
    this.$emit('input', newVal);
  }

  @T_srv.watch('displayPosition', { deep: true })
  onDisplayPositionChange(newVal) {
    this.menuStyle['left'] = newVal?.clientX ? `${newVal.clientX}px` : '0px';
    this.menuStyle['top'] = newVal?.clientY ? `${newVal.clientY}px` : '0px';
  }

  /* 组件名 */
  private G_compName: string = 'oContextMenu';

  /* 组件箱信息对象 */
  private GT_compBoxInfo: ifs.I_compBoxInfo;

  /* 组件箱对象 */
  private GT_compBox: ifs.I_compBox;

  /* 组件箱识别ID */
  private G_compID: string;

  private visible: string = '';

  private show: boolean = false;

  private menuStyle: object = {
    position: 'absolute',
    border: '1px solid #eee'
  };

  get menuWidth() {
    return /\d+px$/.test(this.width.toString())
      ? this.width.toString()
      : `${this.width}px`;
  }

  created() {
    this.onDisplayPositionChange(this.displayPosition);
    this.show = this.value;
    // 如果父组件没有传参，那就产生一个
    this.GT_compBoxInfo = Tsrv.getCompInfo(this.compBoxInfo);
    this.G_compID = this.GT_compBoxInfo.compID;
    this.GT_compBox = this.GT_compBoxInfo.TcompBox;
  }

  mounted() {
    /* 向父组件发送实例 */
    // 如果是一个组件中用了多个本组件，不传compBoxInfo进来，由此传出外部取名记录
    this.$emit('compBoxInfo', this.GT_compBoxInfo);
    this.GT_compBox.addCompMergeName(this.G_compID, this.G_compName, this);
  }

  destroyed() {
    /* 注册组件销毁 */
    this.GT_compBox.removeCompMergeName(this.G_compID, this.G_compName);

    /* 如果父组件传入的compBoxInfo则删除本文件产生的引用,反之是本组件产生的ID统一删除 */
    if (Tsrv.utils.isEmpty(this.compBoxInfo)) {
      this.GT_compBox.removeCompsWithCompID(this.G_compID);
    } else {
      this.GT_compBox.removeCompsMergeName(this.G_compID, [
        `'${this.G_compName}'`
      ]);
    }
  }

  onSelect(e) {
    let isDisabled = false;
    this.list.forEach(item => {
      if (item.name === e) {
        if (item.disabled) isDisabled = true;
      } else {
        if (!Tsrv.noValue(item.children)) {
          item.children.forEach((item2: any) => {
            if (item2.name === e && item2.disabled) isDisabled = true;
          });
        }
      }
    });
    if (isDisabled) return;
    this.callback && this.callback(e); // 假如callback有值是真的，就执行callback  clr
    if (this.callback) {
      this.$emit('on-select', 'null');
    } else {
      this.$emit('on-select', e);
    }
  }

  private disabledClick(e: any) {
    if (e.disabled) {
      document.querySelectorAll('.disabledMenuItem').forEach(dom => {
        dom.classList.remove('ivu-menu-item-active');
      });
    }
  }
}
</script>
<style lang="scss" scoped>
.contextmenu {
  position: absolute;
  z-index: 999;
  .disabledMenuItem {
    color: #ccc;
    cursor: not-allowed;
    &:active {
      transform: translateY(2px) scale(0.98);
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    }
  }
  .menuItemHover {
    &:hover {
      background-color: #f3f3f3;
      color: #2d8cf0;
    }
    &:active {
      transform: translateY(2px) scale(0.98);
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
    }
  }
}
.contextmenu ::v-deep .ivu-menu-item {
  padding: 7px 12px;
  .item-content {
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    .ivu-icon {
      margin-right: 10px;
    }
    span {
      white-space: nowrap;
    }
  }
}
.contextmenu ::v-deep .ivu-menu-submenu-title {
  padding: 10px 12px;
}
</style>
